﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace iMapa.Utils
{
    abstract public class Worker
    {
        /// <summary>
        /// Lock covering stopping and stopped
        /// </summary>
        readonly object stopLock = new object();
        /// <summary>
        /// Whether or not the worker thread has been asked to stop
        /// </summary>
        bool stopping = false;
        /// <summary>
        /// Whether or not the worker thread has stopped
        /// </summary>
        bool stopped = true;

        /// <summary>
        /// Returns whether the worker thread has been asked to stop.
        /// This continues to return true even after the thread has stopped.
        /// </summary>
        public bool Stopping
        {
            get
            {
                lock (stopLock)
                {
                    return stopping;
                }
            }
        }

        /// <summary>
        /// Returns whether the worker thread has stopped.
        /// </summary>
        public bool Stopped
        {
            get
            {
                lock (stopLock)
                {
                    return stopped;
                }
            }
        }

        /// <summary>
        /// Tells the worker thread to stop, typically after completing its 
        /// current work item. (The thread is *not* guaranteed to have stopped
        /// by the time this method returns.)
        /// </summary>
        public void Stop()
        {
            lock (stopLock)
            {
                stopping = true;
            }
        }

        /// <summary>
        /// Called by the worker thread to indicate when it has stopped.
        /// </summary>
        protected void SetStopped()
        {
            lock (stopLock)
            {
                stopping = false;
                stopped = true;
            }
        }

        /// <summary>
        /// Main work loop of the class.
        /// </summary>
        public void Run()
        {
            try
            {
                while (!Stopping)
                {
                    Process();
                }
            }
            finally
            {
                SetStopped();
            }
        }

        abstract protected void Process();


        public void Start(string name)
        {
            if (stopped)
            {
                Thread t = new Thread(this.Run);
                t.Name = name;
                t.IsBackground = true;
                stopped = false;
                t.Start();
            }
            else
            {
                throw new Exception("Starting already started worker thread");
            }
        }

    }
}
